/*
 * CopyRight(C) Kenbin
 */

#include "lsg_config.h"

int LSG::GetPower(int n)
{
    int m = 1;
    int pow = -1;
    for(int i = 0; ; i ++)
    {
	if(n > m) {
	    m *= 2;
	} else if(n == m) {
	    pow = i;
	    break;
	} else {
	    break;
	}
    }

    return pow;
}

static int IsSpace(register int c)
{
    return (c != '\0' && (c & 0x80) == 0 && isspace (c));
}

/*
   ()               -> NULL NULL
   ("")             -> () NULL
   (abc)            -> (abc) NULL
   (a b c)          -> (a) (b) (c) NULL
   ("a b" c)        -> (a b) (c) NULL
   ("a, b", c),     -> (a, b) (c) NULL
   ("a b"c d)       -> (a bc) (d) NULL
   ("\"a b\""c d)   -> ("a b"c) (d) NULL
   ("\\\"a ,b"c,d), -> (\"a ,bc) (d) NULL
 */
const char *LSG::ParseString(register char *result, int result_len, 
	const char *src, int seq, const char **next, char delimitor)
{
    int quoted, len = 0, spec = 0;
    const char *nxt = src, *reslt = result, *ret = NULL;

    if (src != NULL)
    {
	for(; seq >= 0; seq --)
	{
	    for (; IsSpace(*nxt); nxt ++) {
		;
	    }

	    if((quoted = *nxt == '\"')) {
		nxt ++;
	    }

	    for(; *nxt != '\0' && (quoted || (delimitor && *nxt != delimitor || !delimitor 
			    && *nxt != ' ' && *nxt != '\t' && *nxt != '\r' && *nxt != '\n')); nxt ++)
	    {
		if(seq == 0)
		{
		    ret = reslt;
		    if(*nxt == '\\' && (*(nxt + 1) == '\"' || *(nxt + 1) == '\\')) {
			spec = !spec;
		    } else {
			spec = 0;
		    }

		    if(spec == 0 && len < result_len - 1 && 
			    (*nxt != '\"' || nxt > src && *(nxt - 1) == '\\')) {
			*result ++ = *nxt, len ++;
		    }
		}

		if(*nxt == '\"' && nxt > src && *(nxt - 1) != '\\') {
		    quoted = (quoted == 0 ? 1 : 0);
		}
	    }

	    if (*nxt != '\0' && *nxt == delimitor) {
		nxt ++;
	    }
	}

	for(; IsSpace(*nxt); nxt ++) {
	    ;
	}
    }

    *result = '\0';
    if (next != NULL) {
	*next = nxt && *nxt ? nxt : NULL;
    }

    return ret;
}

int LSG::GetBuddyBitSize(int block_count)
{
    if(GetPower(block_count) < 3) {
	return LSG_INVALID_REQUEST_BLOCK_COUNT;
    }

    return block_count / 4;
}

int LSG::VerifyHeadBlock(const char *filename, int block_size, int block_count)
{
    if(block_size <= 0) {
	return LSG_INVALID_BLOCK_SIZE;
    } else if(block_count <= 0) {
	return LSG_INVALID_BLOCK_COUNT;
    }

    int buddybit_size = GetBuddyBitSize(block_count);
    if(buddybit_size < 0) {
	return buddybit_size;
    }

    int fd = open(filename, O_RDWR | O_NONBLOCK, FILE_ACESS_AUTH);
    if(fd < 0) {
	return LSG_OPEN_ERR;
    }

    int e = 0;

    int file_size = lseek(fd, 0, SEEK_END);
    if(file_size < CBuddyFile::HEADBLOCK_SIZE + buddybit_size) {
	e = 0;
    } else {
	char rv[32];
	lseek(fd, 0, SEEK_SET);
	read(fd, rv, sizeof(rv));

	unsigned int *pi = (unsigned int *)rv;
	if(ntohl(pi[1]) == block_size && ntohl(pi[2]) == block_count)
	{
	    e = ntohl(pi[0]);
	    if(e < 0 || e > block_count) {
		e = LSG_INVALID_BLOCK_COUNT;
	    }
	}
    }

    close(fd);
    return e;
}

void LSG::DecodePhysicID(const char *physic_id, int *block_size, 
	int *file_seq, int *buddybit_offset)
{
    char bs[32] = {0};
    char fseq[32] = {0};
    char bb_off[32] = {0};

    ParseString(bs, sizeof(bs), physic_id, 0, NULL, '.');
    ParseString(fseq, sizeof(fseq), physic_id, 1, NULL, '.');
    ParseString(bb_off, sizeof(bb_off), physic_id, 2, NULL, '.');

    *block_size = atoi(bs);
    *file_seq = atoi(fseq);
    *buddybit_offset = atoi(bb_off);
}
